
#include <cstdio>
#include <BFile>
#include <BEntry>
#include <BFolder>
#include <BReadWrite>
#include <BTreeItem>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BMessageBox>
#include <BStyle>
#include <BLabel>
#include <BCursor>
#include <BHtmlWidget>
#include <BTextEdit>
#include <BSonDocument>
#include <BXmlDocument>
#include <BApplication>
#include <BSystem>
#include <BDrag>
#include <BShortcut>

#include "ResourceDialog.h"
#include "MainWindow.h"

MainWindow::MainWindow()
{
	_fileDialog = new BFileDialog();
	_fileDialog->setFrameless(true);
	_fileDialog->setEditable(true);

	_messageBox = new BMessageBox();
	_messageBox->setFrameless(true);

	initMenus();

	_menuBar = new BMenuBar();
	_menuBar->setSpacing(3);
	_menuBar->addMenu(_fileMenu);
	_menuBar->addMenu(_editMenu);
	_menuBar->addMenu(_viewMenu);
	_menuBar->addMenu(_toolMenu);

	BWidget* toolBar = new BWidget("toolbar");
	{
		_openButton = new BButton(_fileMenu->action("Open"));
		_saveButton = new BButton(_fileMenu->action("Save"));
		_saveAsButton = new BButton(_fileMenu->action("Save-As"));
		_removeButton = new BButton(_itemMenu->action("Remove"));
		BButton* freshButton = new BButton(_itemMenu->action("Refresh"));
		BButton* cleanButton = new BButton(_itemMenu->action("Clean"));
		_checkButton = new BButton(_editMenu->action("Check"));
		_buildButton = new BButton(_editMenu->action("Build"));
		_targetEdit = new BLineEdit();
		{
			_browseButton = new BButton("...");
			_browseButton->setSizePolicy(Policy_Preferred);
			BLayout* layout = new BLayout(_targetEdit, Part_Right);
			layout->setWidget(_browseButton, Align_Center);
		}

		BHBoxLayout* toolLayout = new BHBoxLayout(toolBar);
		toolLayout->addWidget(_openButton);
		toolLayout->addWidget(_saveButton);
		toolLayout->addWidget(_saveAsButton);
		toolLayout->addWidget(_removeButton);
		toolLayout->addSpacer(36);
		toolLayout->addWidget(_checkButton);
		toolLayout->addWidget(freshButton);
		toolLayout->addWidget(cleanButton);
		toolLayout->addWidget(_buildButton);
		toolLayout->addSpacer(36);
		toolLayout->addWidget(new BLabel("output"));
		toolLayout->addWidget(_targetEdit, 10);
		toolLayout->addSpring(10);
	}

	BGridLayout* gridLayout = new BGridLayout();
	gridLayout->setSplitable(true);
	gridLayout->setRowSpacing(5);
	gridLayout->setColumnSpacing(5);
	{
		_treeWidget = new BTreeWidget("Resource Manager");
		_treeWidget->setName("resource");

		_lineEdit = new BLineEdit(_treeWidget);
		_lineEdit->setName("item-text-edit");
		_lineEdit->hide();

		_propertyGroupBox = new PropertyBoard();

		_outputEdit = new BTextEdit("Output");
		_outputEdit->setReadOnly(true);

		_contentWidget = new ContentBoard();

		gridLayout->addWidget(0, 0, _treeWidget);
		gridLayout->addWidget(0, 1, _propertyGroupBox);
		gridLayout->addWidget(1, 0, _outputEdit);
		gridLayout->addWidget(1, 1, _contentWidget);
		gridLayout->setColumnStretch(0, 10);
		gridLayout->setColumnStretch(1, 1);
		gridLayout->setRowStretch(0, 5);
		gridLayout->setRowStretch(1, 1);
	}

	_statusBar = new BStatusBar();

	BVBoxLayout* layout = new BVBoxLayout(this);
	layout->addWidget(_menuBar, 0);
	layout->addWidget(toolBar, 0);
	layout->addLayout(gridLayout);
	layout->addWidget(_statusBar, 0);

	BShortcut* shortcut = new BShortcut("del");

	connect(shortcut, Signal_Triggered, &MainWindow::slotDeleteShortcutTriggered);

	connect(_treeWidget, Signal_ItemSelected, &MainWindow::slotTreeItemSelected);
	connect(_treeWidget, Signal_ItemClicked, &MainWindow::slotTreeItemClicked);
	connect(_treeWidget, Signal_ItemRightClicked, &MainWindow::slotTreeItemRightClicked);
	connect(_treeWidget, Signal_ItemDoubleClicked, &MainWindow::slotTreeItemDoubleClicked);
	connect(_treeWidget, Signal_Dragged, &MainWindow::slotWorkspaceDragged);
	connect(_treeWidget, Signal_DragMoved, &MainWindow::slotWorkspaceDragMoved);
	connect(_treeWidget, Signal_DragDropped, &MainWindow::slotWorkspaceDragDropped);
	connect(_browseButton, Signal_Clicked, &MainWindow::slotBrowseButtonClicked);
	connect(_lineEdit, Signal_EditFinished, &MainWindow::slotLineEditFinished);
	connect(_targetEdit, Signal_EditFinished, &MainWindow::slotTargetEditFinished);
	connect(_outputEdit, Signal_DoubleClicked, &MainWindow::slotOutputEditDoubleClicked);

	_saveButton->setEnabled(false);

}
MainWindow::~MainWindow()
{

}

bool MainWindow::openFile(const BString& fileName)
{
	if (fileName.empty())
		return false;
	this->emit("file-opened", fileName);
	if (fileName.endWith(".src"))
	{
		_treeWidget->clearItems();
		BSonDocument document;
		document.load(fileName);
		BApplication::setCurrentPath(fileName.path());
		for (int i = 0; i < document.nodeCount(); i++)
		{
			BSonNode* node = document.node(i);
			if (node->name() == "?config")
			{
				_targetEdit->setText(node->attrib("output"));
				continue;
			}
			BTreeItem* topItem = createTreeItem(node);
			_treeWidget->addItem(topItem);
			freshItemIcons(topItem);
		}
		_checkButton->click();
		return true;
	}
	if (fileName.endWith(".xrc"))
	{
		_treeWidget->clearItems();
		BXmlDocument document;
		document.load(fileName);
		BApplication::setCurrentPath(fileName.path());
		for (int i = 0; i < document.nodeCount(); i++)
		{
			BXmlNode* node = document.node(i);
			if (node->name() == "?config")
			{
				_targetEdit->setText(node->attrib("output"));
				continue;
			}
			BTreeItem* topItem = createTreeItem(node);
			_treeWidget->addItem(topItem);
			freshItemIcons(topItem);
		}
		_checkButton->click();
		return true;
	}
	return false;
}
bool MainWindow::saveFile(const BString& fileName)
{
	if (fileName.empty())
		return false;
	if (fileName.endWith(".src"))
	{
		BSonDocument document;
		document.setFormat("}\n");
		if (BSonNode* configNode = document.addNode("?config"))
		{
			configNode->setAttrib("output", _targetEdit->text());
		}
		for (int i = 0; i < _treeWidget->itemCount(); i++)
		{
			BTreeItem* topItem = _treeWidget->item(i);
			BSonNode* node = createSonNode(topItem);
			document.addNode(node);
		}
		if (!document.save(fileName))
		{
			BString text("Save source file ");
			text << fileName + " Failed.";
			Button result = BMessageBox::Warning(this, "Warning", text);
			return false;
		}
		return true;
	}
	if (fileName.endWith(".xrc"))
	{
		BXmlDocument document;
		document.setFormat("<>\n</>\n");
		if (BXmlNode* configNode = document.addNode("?config"))
		{
			configNode->setAttrib("output", _targetEdit->text());
		}
		for (int i = 0; i < _treeWidget->itemCount(); i++)
		{
			BTreeItem* topItem = _treeWidget->item(i);
			BXmlNode* node = createXmlNode(topItem);
			document.addNode(node);
		}
		if (!document.save(fileName))
		{
			BString text("Save source file ");
			text << fileName + " Failed.";
			Button result = BMessageBox::Warning(this, "Warning", text);
			return false;
		}
		return true;
	}
	return false;
}

void MainWindow::initMenus()
{
	_fileMenu = new BMenu("File");
	{
		BAction* newAction = _fileMenu->addAction("New");
		BAction* openAction = _fileMenu->addAction("Open");
		BAction* saveAction = _fileMenu->addAction("Save");
		BAction* saveAsAction = _fileMenu->addAction("Save-As");
		_fileMenu->addSeparator();
		BAction* quitAction = _fileMenu->addAction("Quit");
		connect(newAction, Signal_Triggered, &MainWindow::slotNewActionTriggered);
		connect(openAction, Signal_Triggered, &MainWindow::slotOpenActionTriggered);
		connect(saveAction, Signal_Triggered, &MainWindow::slotSaveActionTriggered);
		connect(saveAsAction, Signal_Triggered, &MainWindow::slotSaveAsActionTriggered);
	}

	_editMenu = new BMenu("Edit");
	{
		_editMenu->addAction("Undo");
		_editMenu->addAction("Redo");
		_editMenu->addSeparator();
		_editMenu->addAction("Copy");
		_editMenu->addAction("Cut");
		_editMenu->addAction("Paste");
		BAction* checkAction = _editMenu->addAction("Check");
		BAction* buildAction = _editMenu->addAction("Build");
		connect(checkAction, Signal_Triggered, &MainWindow::slotCheckActionTriggered);
		connect(buildAction, Signal_Triggered, &MainWindow::slotBuildActionTriggered);
	}

	_viewMenu = new BMenu("View");
	{
		BAction* resouceAction = _viewMenu->addAction("Resource");
		resouceAction->setCheckable(true);
		connect(resouceAction, Signal_Triggered, &MainWindow::slotResourceActionTriggered);
	}

	_toolMenu = new BMenu("Tool");

	_itemMenu = new BMenu();
	_addFilesAction = _itemMenu->addAction("Add files");
	_addFolderAction = _itemMenu->addAction("Add folder");
	_addFilterAction = _itemMenu->addAction("Add filter");
	_refreshAction = _itemMenu->addAction("Refresh");
	_cleanAction = _itemMenu->addAction("Clean");
	_removeAction = _itemMenu->addAction("Remove");

	connect(_addFilesAction, Signal_Triggered, &MainWindow::slotAddFilesActionTriggered);
	connect(_addFolderAction, Signal_Triggered, &MainWindow::slotAddFolderActionTriggered);
	connect(_addFilterAction, Signal_Triggered, &MainWindow::slotAddFilterActionTriggered);
	connect(_refreshAction, Signal_Triggered, &MainWindow::slotRefreshActionTriggered);
	connect(_cleanAction, Signal_Triggered, &MainWindow::slotCleanActionTriggered);
	connect(_removeAction, Signal_Triggered, &MainWindow::slotRemoveActionTriggered);
}

void MainWindow::signTitleChanged(bool changed)
{
	const BString& title = this->title();
	if (changed)
	{
		if (!title.endWith('*'))
		{
			this->setTitle(title + '*');
		}
		_saveButton->setEnabled(true);
	}
	else
	{
		if (title.endWith('*'))
		{
			this->setTitle(title - '*');
		}
		_saveButton->setEnabled(false);
	}
}
BString MainWindow::findValidName(const char* name, const BTreeItem* parent)
{
	BString realName;
	int number = 0;
	while (number < 9999)
	{
		realName.reset();
		realName << name << number++;
		if (parent)
		{
			if (parent->child(realName))
				continue;
		}
		else
		{
			if (_treeWidget->item(realName))
				continue;
		}
		break;
	}
	return realName;
}
BSonNode* MainWindow::createSonNode(const BTreeItem* item)
{
	BSonNode* node = new BSonNode();
	if (BEntry* entry = item->asset())
	{
		if (entry->attrib() & Attrib_Folder)
			node->setName("folder");
		else
			node->setName("file");
		const BString& name = item->text();
		const BString& path = item->property("path");
		if (name != path)
			node->setAttrib("name", name);
		node->setAttrib("path", path);
	}
	else
	{
		node->setName("filter");
		node->setAttrib("name", item->text());
	}
	if (item->childCount())
	{
		node->setFormat("{\n;\n}\n");
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		const BTreeItem* child = item->child(i);
		node->addChild(createSonNode(child));
	}
	return node;
}
BXmlNode* MainWindow::createXmlNode(const BTreeItem* item)
{
	BXmlNode* node = new BXmlNode();
	if (BEntry* entry = item->asset())
	{
		if (entry->attrib() & Attrib_Folder)
			node->setName("folder");
		else
			node->setName("file");
		if (item->text() != entry->name())
			node->setAttrib("name", item->text());
		const BString& path = item->property("path");
		node->setAttrib("path", path);
	}
	else
	{
		node->setName("filter");
		node->setAttrib("name", item->text());
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		const BTreeItem* child = item->child(i);
		node->addChild(createXmlNode(child));
	}
	return node;
}
BTreeItem* MainWindow::createTreeItem(const BSonNode* node)
{
	if (node->name() == "file")
	{
		const BString& name = node->attrib("name");
		const BString& path = node->attrib("path");
		BTreeItem* item = new BTreeItem();
		if (name.size())
			item->setText(name);
		else
			item->setText(path);
		item->setProperty("path", path);
		BString fullPath = BFolder::AbsolutePath(path);
		item->setAsset(BEntry::Open(fullPath));
		return item;
	}
	else if (node->name() == "folder")
	{
		const BString& name = node->attrib("name");
		const BString& path = node->attrib("path");
		BTreeItem* item = new BTreeItem();
		if (name.size())
			item->setText(name);
		else
			item->setText(path.name());
		item->setProperty("path", path);
		AutoWorkPath workpath(path);
		item->setAsset(BEntry::Open(BApplication::currentPath()));
		for (int i = 0; i < node->childCount(); i++)
		{
			const BSonNode* child = node->child(i);
			item->addChild(createTreeItem(child));
		}
		return item;
	}
	if (node->name() == "filter")
	{
		BTreeItem* item = new BTreeItem();
		item->setText(node->attrib("name"));
		for (int i = 0; i < node->childCount(); i++)
		{
			const BSonNode* child = node->child(i);
			item->addChild(createTreeItem(child));
		}
		return item;
	}
	return 0;
}
BTreeItem* MainWindow::createTreeItem(const BXmlNode* node)
{
	if (node->name() == "file")
	{
		const BString& name = node->attrib("name");
		const BString& path = node->attrib("path");
		BTreeItem* item = new BTreeItem();
		if (name.size())
			item->setText(name);
		else
			item->setText(path.name());
		item->setProperty("path", path);
		BString fullPath = BFolder::AbsolutePath(path);
		item->setAsset(BEntry::Open(fullPath));
		return item;
	}
	else if (node->name() == "folder")
	{
		const BString& name = node->attrib("name");
		const BString& path = node->attrib("path");
		BTreeItem* item = new BTreeItem();
		if (name.size())
			item->setText(name);
		else
			item->setText(path.name());
		item->setProperty("path", path);
		AutoWorkPath workpath(path);
		item->setAsset(BEntry::Open(BApplication::currentPath()));
		for (int i = 0; i < node->childCount(); i++)
		{
			const BXmlNode* child = node->child(i);
			item->addChild(createTreeItem(child));
		}
		return item;
	}
	if (node->name() == "filter")
	{
		BTreeItem* item = new BTreeItem();
		item->setText(node->attrib("name"));
		for (int i = 0; i < node->childCount(); i++)
		{
			const BXmlNode* child = node->child(i);
			item->addChild(createTreeItem(child));
		}
		return item;
	}
	return 0;
}

void MainWindow::cleanLostItems(BTreeItem* item)
{
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		if (child->property("path").valid() && child->asset().empty())
		{
			BString message('\t', child->level());
			message << child->text() << '\n';
			_outputEdit->addText(message);
			item->removeChild(i--);
			_cleanCount++;
			continue;
		}
		cleanLostItems(child);
	}
}
void MainWindow::freshItemIcons(BTreeItem* item)
{
	const BStyle* style = this->realStyle();
	if (item->property("path").valid())
	{
		if (BEntry* entry = item->asset())
		{
			BIcon* icon = 0;
			if (entry->attrib() & Attrib_Folder)
				icon = style->icon("folder");
			if (!icon)
				icon = BSystem::EntryIcon(entry->path());
			item->setIcon(icon);
		}
		else
		{
			BIcon* icon = style->icon("lost");
			item->setIcon(icon);
		}
	}
	else
	{
		BIcon* icon = style->icon("filter");
		item->setIcon(icon);
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		freshItemIcons(child);
	}
}
void MainWindow::refreshResource(BTreeItem* item)
{
	bool changed = false;
	if (BEntry* entry = item->asset())
	{
		bool enabled = BEntry::Exist(entry->path());
		entry->setEnabled(enabled);
		if (entry->attrib() == Attrib_Folder)
		{
			_outputEdit->addText("> fresh folder : ");
			_outputEdit->addText(entry->path());
			_outputEdit->addText("\n");
			BFolder folder(entry->path());
			if (folder.open())
			{
				BString newMessage;
				for (int i = 0; i < folder.entryCount(); i++)
				{
					BEntry* entry = folder.entry(i);
					if (entry->name().beginWith('.'))
						continue;
					if (!item->child(entry->name()))
					{
						BTreeItem* child = item->addChild(entry->name());
						child->setAsset(entry);
						child->setName(entry->name());
						child->setProperty("path", entry->name());
						newMessage.append('\t', item->level() + 1);
						newMessage << item->path() << '/' << child->text() << "\n";
						_freshCount++;
						changed = true;
					}
				}
				if (newMessage.size())
				{
					int addCount = newMessage.count('\n');
					_outputEdit->addText("> new entry : ");
					_outputEdit->addText(addCount);
					_outputEdit->addText('\n');
					_outputEdit->addText(newMessage);
				}

				BString lostMessage;
				for (int i = 0; i < item->childCount(); i++)
				{
					BTreeItem* child = item->child(i);
					if (!folder.contain(child->text()))
					{
						item->setAsset(BValue());
						lostMessage.append('\t', item->level() + 1);
						lostMessage << item->path() << '/' << child->text() << "\n";
						_freshCount++;
						changed = true;
					}
				}
				if (lostMessage.size())
				{
					int lostCount = lostMessage.count('\n');
					_outputEdit->addText("> lost entry : ");
					_outputEdit->addText(lostCount);
					_outputEdit->addText('\n');
					_outputEdit->addText(lostMessage);
				}

			}
		}
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		refreshResource(child);
	}
	if (changed)
	{
		signTitleChanged(true);
	}
}
void MainWindow::cleanResource(BTreeItem* item)
{
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		BEntry* entry = child->asset();
		if (entry && !entry->enabled())
		{
			item->removeChild(child);
		}
	}
}
void MainWindow::writeResource(BTreeItem* item, BString& infos, BString& datas)
{
	BEntry* entry = item->asset();
	if (entry && entry->attrib() & Attrib_File)
	{
		BByteArray bytes;
		if (BFile::Load(entry->path(), bytes))
		{
			BString path = item->path();
			infos << '\t' << path << '(' << bytes.size() << ");\n";
			datas << "//" << path << '(' << bytes.size() << ")";
			char cstr[5];
			for (int i = 0; i < bytes.size(); i++)
			{
				if (i % 16 == 0)
					datas << '\n' << '\t';
				bByteToHex(cstr, bytes[i]);
				datas << "0x" << cstr << ',';
			}
			datas << '\n';
		}
		else
		{
			BString message("Error : Open file ");
			message << entry->path() + " Failed.";
			_messageBox->addText(message);
			return;
		}
	}

	BString text = _outputEdit->lineCount() + 1;
	text << " : ";
	text.append('\t', item->level());
	text << item->text() << ";\n";
	_outputEdit->addText(text);

	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		writeResource(child, infos, datas);
	}
}
void MainWindow::checkResource(BTreeItem* item, BString& infos)
{
	if (item->property("path").valid())
	{
		if (item->asset().empty())
		{
			infos.append('\t', item->level());
			infos << item->path() << "\n";
		}
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		checkResource(child, infos);
	}
}

void MainWindow::slotBrowseButtonClicked(BObject* object, const BValue& value)
{
	BString outputPath = _fileDialog->openEntry("Choose build output path", _targetEdit->text());
	if (outputPath.size())
	{
		BString currentPath = BApplication::currentPath();
		if (outputPath.beginWith(currentPath))
		{
			outputPath.remove(currentPath);
			outputPath.remove('/');
		}
		_targetEdit->setText(outputPath);
		signTitleChanged(true);
	}
}
void MainWindow::slotLineEditFinished(BObject* object, const BValue& value)
{
	if (BTreeItem* item = _lineEdit->asset())
	{
		item->setText(_lineEdit->text());
		_lineEdit->hide();
		signTitleChanged(true);
	}
}
void MainWindow::slotTargetEditFinished(BObject* object, const BValue& value)
{
	signTitleChanged(true);
}
void MainWindow::slotOutputEditDoubleClicked(BObject* object, const BValue& value)
{
	BPoint pos = value;
	int line = _outputEdit->lineAt(pos);
	const BString& text = _outputEdit->lineText(line);
	int split = text.find(':');
	BString path;
	text.substr(path, 0, split);
	path.trimmed();
	if (BTreeItem* item = _treeWidget->locate(path))
	{
		_treeWidget->setSelection(item);
		_treeWidget->scrollToItem(item, Align_VCenter);
	}
}
void MainWindow::slotTreeItemSelected(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (item->selected())
	{
		_propertyGroupBox->setAsset(item);
		_contentWidget->setAsset(item);
	}
	else
	{
		_propertyGroupBox->setAsset(BValue());
		_contentWidget->setAsset(BValue());
	}
}
void MainWindow::slotTreeItemClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (_lineEdit->asset() == item)
	{
		if (item)
		{
			BSize shellSize = _lineEdit->shellSize();
			BRect textRect = item->textRect();
			_lineEdit->setSize(_lineEdit->sizeHint());
			_lineEdit->setPos(textRect.leftTop());
			_lineEdit->setWidth(int(textRect.width() * 1.5));
			_lineEdit->setText(item->text());
			_lineEdit->move(-shellSize.width() / 2, -shellSize.height() / 2);
			_lineEdit->popup();
		}
	}
	else
	{
		_lineEdit->setAsset(item);
		_lineEdit->hide();
	}
}
void MainWindow::slotTreeItemRightClicked(BObject* object, const BValue& value)
{
	BPoint pos = BCursor::GetPos(_treeWidget);
	_itemMenu->setParent(_treeWidget);
	_itemMenu->setPos(pos);
	if (_treeWidget->selectedItemCount() == 0)
	{
		_addFilesAction->setVisible(true);
		_addFolderAction->setVisible(true);
		_addFilterAction->setVisible(true);
		_removeAction->setVisible(false);
	}
	if (_treeWidget->selectedItemCount() == 1)
	{
		BTreeItem* selectedItem = _treeWidget->selectedItem();
		if (selectedItem->asset().empty())
		{
			_addFilesAction->setVisible(true);
			_addFolderAction->setVisible(true);
			_addFilterAction->setVisible(true);
		}
		else
		{
			_addFilesAction->setVisible(false);
			_addFolderAction->setVisible(false);
			_addFilterAction->setVisible(false);
		}
		_removeAction->setVisible(true);
	}
	if (_treeWidget->selectedItemCount() > 1)
	{
		_addFilesAction->setVisible(false);
		_addFolderAction->setVisible(false);
		_addFilterAction->setVisible(false);
		_removeAction->setVisible(true);
	}
	_itemMenu->popup();
}
void MainWindow::slotTreeItemDoubleClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (!item)
		return;
	const HeadInfo* info = item->asset();
	if (info && info->htmlEntry)
	{
		const BString& htmlName = info->htmlEntry->path();
	}
}
void MainWindow::slotWorkspaceDragged(BObject* object, const BValue& value)
{
	const BPoint& pos = value;
	if (BTreeItem* item = _treeWidget->query("hovered-item"))
	{
		BDrag* drag = new BDrag();
		drag->setText("move item");
		drag->setValue(item);
		if (drag->execute())
		{

		}
	}
}
void MainWindow::slotWorkspaceDragMoved(BObject* object, const BValue& value)
{
	BDrag* drag = value;
	const BPoint& pos = drag->pos();
	BTreeItem* hoveredItem = _treeWidget->itemAt(pos);
	if (drag->value() == hoveredItem)
		this->setCursor(CursorType::Cursor_Forbidden);
	else
		this->setCursor(CursorType::Cursor_None);

}
void MainWindow::slotWorkspaceDragDropped(BObject* object, const BValue& value)
{
	if (BDrag* drag = value)
	{
		BTreeItem* item = drag->value();
		const BPoint& pos = drag->pos();
		BTreeItem* hoveredItem = _treeWidget->itemAt(pos);
		if (hoveredItem && item->parent() != hoveredItem)
		{
			hoveredItem->addChild(item);
		}
	}
}

void MainWindow::slotNewActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotOpenActionTriggered(BObject* object, const BValue& value)
{
	const BString& fileName = BFileDialog::OpenFile(0, "Open file");
	if (fileName.empty())
		return;
	_treeWidget->clearItems();
	if (openFile(fileName))
	{
		this->setName(fileName);
		this->setTitle(fileName);
		this->emit("file-opened", fileName);
	}
	else
	{
		BString text("Open resource file failed!\n");
		text << fileName;
		BMessageBox::Warning(this, "Warning", text);
	}
}
void MainWindow::slotSaveActionTriggered(BObject* object, const BValue& value)
{
	if (this->name().empty())
	{
		const BString& fileName = BFileDialog::SaveFile(0, "Save Resource file", "", "*.src;*.xrc;");
		if (fileName.empty())
			return;
		this->setName(fileName);
		this->setTitle(fileName);
	}
	const BString& fileName = this->name();
	if (!saveFile(fileName))
	{
		BString text("Save resource file successful!\n");
		text << fileName;
		BMessageBox::Information(this, "Information", text);
	}
	signTitleChanged(false);
}
void MainWindow::slotSaveAsActionTriggered(BObject* object, const BValue& value)
{
	const BString& fileName = BFileDialog::SaveFile(0, "Save Resource file", "", "*.src;*.xrc;");
	if (fileName.empty())
		return;
	if (!saveFile(fileName))
	{
		BString text("Save resource file successful!\n");
		text << fileName;
		BMessageBox::Information(this, "Information", text);
	}
}
void MainWindow::slotCheckActionTriggered(BObject* object, const BValue& value)
{
	BString text;
	text << "====== Start check " << _treeWidget->itemCount() << " : " << BFolder::RelativePath(this->name()) << " ======\n";
	_outputEdit->addText(text);
	text.reset();
	for (int i = 0; i < _treeWidget->itemCount(); i++)
	{
		BTreeItem* item = _treeWidget->item(i);
		checkResource(item, text);
	}
	text << "------ Lost resource files : " << text.count('\n') << " ------\n";
	_outputEdit->addText(text);
	_outputEdit->scrollTo(Part_Bottom);
}
void MainWindow::slotBuildActionTriggered(BObject* object, const BValue& value)
{
	if (this->title().endWith('*'))
	{
		const BString& fileName = this->name();
		if (!saveFile(fileName))
		{
			BString text("Save resource file failed!\nBefore build please save this resource project.");
			text << fileName;
			BMessageBox::Information(this, "Information", text);
			return;
		}
		signTitleChanged(false);
	}

	BString text;
	text << "====== Start build " << _treeWidget->itemCount() << " : " << BFolder::RelativePath(this->name()) << " ======\n";
	_outputEdit->addText(text);

	BString name = this->name().name();
	name -= name.ext();
	name -= '.';

	BString fileName = _targetEdit->text();
	if (fileName.empty())
	{
		fileName = this->name().path();
		if (fileName.empty())
			fileName = BApplication::currentPath();
		fileName << '/' << name << ".cpp";
	}
	else if (!BFile::Exist(fileName))
	{
		int res = _messageBox->question("Question", "file is not exist, Do you want to create ?", Button_Yes | Button_No);
		if (res != Button_Yes)
			return;
		BFile::Create(fileName);
	}

	BFile file(fileName);
	if (!file.open(IO_WriteText))
	{
		BString text("Save source file ");
		text << fileName + " Failed.";
		Button result = BMessageBox::Warning(this, "Warning", text);
		return;
	}

	name.replace('-', '_');

	BString info_text("static const char* ");
	info_text << name << "_info = R\"(\n";
	BString data_text("static const unsigned char ");
	data_text << name << "_data[] = {\n";

	for (int i = 0; i < _treeWidget->itemCount(); i++)
	{
		BTreeItem* topItem = _treeWidget->item(i);
		writeResource(topItem, info_text, data_text);
	}
	data_text -= ',';
	data_text << "};\n";
	info_text << ")\";\n";

	file.write("\n#include <BReadWrite>\nusing namespace BWE;\n");
	file.write(info_text);
	file.write(data_text);
	file.write("namespace {\n");
	file.write("\tstruct initializer {\n");
	file.write("\t\tinitializer(){RegistResource(");
	file << name << "_info, " << name << "_data);}\n";
	file.write("\t\t~initializer(){UnregistResource(");
	file << name << "_info);}\n";
	file.write("\t}dummy;\n}\n");

	AutoWorkPath workpath(fileName.path());
	text.reset();
	text << "output => " << BFolder::RelativePath(fileName) << '\n';
	_outputEdit->addText(text);

	text.reset();
	text << "------ Build resource files : " << _treeWidget->itemCount() << " ------\n";
	_outputEdit->addText(text);
	_outputEdit->scrollTo(Part_Bottom);
}
void MainWindow::slotResourceActionTriggered()
{
	static ResourceDialog* appResDialog = new ResourceDialog(this);
	appResDialog->popup();
}

void MainWindow::slotAddFilesActionTriggered(BObject* object, const BValue& value)
{
	const BStringList& fileNamelst = BFileDialog::OpenFiles(this, "Open file");
	if (fileNamelst.empty())
		return;

	BTreeItem* parent = 0;
	if (_treeWidget->selectedItemCount() == 1)
		parent = _treeWidget->selectedItem();

	for (int i = 0; i < fileNamelst.size(); i++)
	{
		BString fileName = fileNamelst[i];
		BTreeItem* item = new BTreeItem(fileName.name());
		item->setName(fileName);
		item->setAsset(BEntry::Open(fileName));
		item->setProperty("path", BFolder::RelativePath(fileName));
		if (parent)
			parent->addChild(item);
		else
			_treeWidget->addItem(item);
		freshItemIcons(item);
	}
	signTitleChanged(true);
}
void MainWindow::slotAddFolderActionTriggered(BObject* object, const BValue& value)
{
	const BStringList& fileNames = BFileDialog::OpenFolders(0, "Open folders");
	if (fileNames.empty())
		return;

	BTreeItem* parent = 0;
	if (_treeWidget->selectedItemCount() == 1)
		parent = _treeWidget->selectedItem();

	for (const BString& fileName : fileNames)
	{
		BTreeItem* item = new BTreeItem(fileName.name());
		item->setName(fileName);
		item->setAsset(BEntry::Open(fileName));
		item->setProperty("path", BFolder::RelativePath(fileName));

		refreshResource(item);

		if (parent)
			parent->addChild(item);
		else
			_treeWidget->addItem(item);
		freshItemIcons(item);
	}

	signTitleChanged(true);
}
void MainWindow::slotAddFilterActionTriggered(BObject* object, const BValue& value)
{
	BTreeItem* parent = 0;
	if (_treeWidget->selectedItemCount() == 1)
		parent = _treeWidget->selectedItem();

	BString text = findValidName("NewFilter");
	BTreeItem* item = new BTreeItem(text);
	if (parent)
		parent->addChild(item);
	else
		_treeWidget->addItem(item);
	freshItemIcons(item);
	signTitleChanged(true);
}
void MainWindow::slotRefreshActionTriggered(BObject* object, const BValue& value)
{
	_outputEdit->setText("======================= Start refresh =======================\n");
	_freshCount = 0;
	if (_treeWidget->selectedItemCount())
	{
		for (int i = 0; i < _treeWidget->selectedItemCount(); i++)
		{
			BTreeItem* item = _treeWidget->selectedItem(i);
			refreshResource(item);
			freshItemIcons(item);
		}
	}
	else
	{
		for (int i = 0; i < _treeWidget->itemCount(); i++)
		{
			BTreeItem* item = _treeWidget->item(i);
			refreshResource(item);
			freshItemIcons(item);
		}
	}
	_outputEdit->addText("-------------- Finish refresh :  ");
	_outputEdit->addText(_freshCount);
	_outputEdit->addText(" --------------\n");
}
void MainWindow::slotCleanActionTriggered(BObject* object, const BValue& value)
{
	_outputEdit->setText("======================= Start clean =======================\n");
	_cleanCount = 0;
	if (int selectedCount = _treeWidget->selectedItemCount())
	{
		for (int i = 0; i < selectedCount; i++)
		{
			BTreeItem* item = _treeWidget->selectedItem(i);
			cleanLostItems(item);
		}
	}
	else
	{
		for (int i = 0; i < _treeWidget->itemCount(); i++)
		{
			BTreeItem* item = _treeWidget->item(i);
			if (item->property("path").valid() && item->asset().empty())
			{
				_outputEdit->addText(item->text());
				_outputEdit->addText('\n');
				_treeWidget->removeItem(i--);
				_cleanCount++;
				continue;
			}
			cleanLostItems(item);
		}
	}
	_outputEdit->addText("-------------- Finish clean :  ");
	_outputEdit->addText(_cleanCount);
	_outputEdit->addText(" --------------\n");
	if (_cleanCount)
	{
		signTitleChanged(true);
	}
}
void MainWindow::slotRemoveActionTriggered(BObject* object, const BValue& value)
{
	const BTreeItemArray selection = _treeWidget->selection();
	for (int i = 0; i < selection.size(); i++)
	{
		BTreeItem* item = selection(i);
		_treeWidget->removeItem(item);
	}
	signTitleChanged(true);
}

void MainWindow::slotDeleteShortcutTriggered()
{
	BTreeItemArray selection = _treeWidget->selection();
	if (selection.size())
	{
		BString message("Entries removed :\n");
		for (int i = 0; i < selection.size(); i++)
		{
			BTreeItem* item = selection[i];
			message.append('\t', item->level());
			message << item->text() << '\n';
			_treeWidget->removeItem(item);
		}
		message -= ',';
		signTitleChanged(true);
		_outputEdit->addText(message);
	}
}

void MainWindow::closeEvent(const BEvent& event)
{
	if (_saveButton->enabled())
	{
		const BStyle* style = this->realStyle();
		Button button = BMessageBox::Warning("Warning", style->text("warning-close-save"), Button_Save | Button_Cancel);
		if (button == Button_Cancel)
		{
			event.accept(false);
			return;
		}
		if (button == Button_Save)
		{
			_saveButton->click();
		}
	}
	BApplication::exit(0);
}

void MainWindow::updateEvent(const BEvent& event)
{
	if (!_saveAsButton->enabled() && _saveButton->enabled())
	{
		_saveAsButton->setEnabled(true);
	}
}

void MainWindow::styleEvent(const BEvent& event)
{
	BMainWindow::styleEvent(event);
	const BStyle* style = event.value();
	const BString& text = style->text("warning-close-save");
	for (int i = 0; i < _treeWidget->itemCount(); i++)
	{
		BTreeItem* item = _treeWidget->item(i);
		freshItemIcons(item);
	}

	_addFilesAction->setIcon(style->icon("add-files"));
	_addFolderAction->setIcon(style->icon("add-folder"));
	_addFilterAction->setIcon(style->icon("add-filter"));
	_refreshAction->setIcon(style->icon("refresh"));
	_cleanAction->setIcon(style->icon("clean"));
	_removeAction->setIcon(style->icon("remove"));

	_fileMenu->action("New")->setTips(style->text("tips-new"));
	_fileMenu->action("Open")->setTips(style->text("tips-open"));
	_fileMenu->action("Save")->setTips(style->text("tips-save"));
	_fileMenu->action("Save-As")->setTips(style->text("tips-save-as"));
	_fileMenu->action("Quit")->setTips(style->text("tips-quit"));

	_addFilesAction->setTips(style->text("tips-add-files"));
	_addFolderAction->setTips(style->text("tips-add-folder"));
	_addFilterAction->setTips(style->text("tips-add-filter"));
	_refreshAction->setTips(style->text("tips-refresh"));
	_cleanAction->setTips(style->text("tips-clean"));
	_removeAction->setTips(style->text("tips-remove"));
	_checkButton->setTips(style->text("tips-check"));
	_buildButton->setTips(style->text("tips-build"));

}
